/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#ifndef WORLD_HPP
#define WORLD_HPP

#include <boost/random/linear_congruential.hpp>
#include <boost/signals.hpp>
#include <list>
#include <map>
#include <vector>

#include "ForwardDecls.hpp"
#include "Projectile.hpp"
#include "Spatial.hpp"
#include "Squad.hpp"

namespace spelprog2 {
namespace sim {

struct WorldSignals {
    // World ==================================================================

    typedef boost::signal<void (const sim::World & world)> WorldUpdated;

    WorldUpdated    worldUpdated;

    // Units ==================================================================

    typedef boost::signal<void (Unit::ConstPointer, sim::Int playerId, sim::Int squadId)> UnitAdded;
    typedef boost::signal<void (Unit::ConstPointer)> UnitRemoved;

    UnitAdded       unitAdded;
    UnitRemoved     unitRemoved;

    // Projectiles ============================================================

    typedef boost::signal<void (const Projectile &)> ProjectileAdded;
    typedef boost::signal<void (const Projectile &)> ProjectileRemoved;

    ProjectileAdded     projectileAdded;
    ProjectileRemoved   projectileRemoved;

    // Squads =================================================================

    typedef boost::signal<void (Squad::ConstPointer, sim::Int playerId)> SquadAdded;
    typedef boost::signal<void (Squad::ConstPointer)> SquadRemoved;

    SquadAdded      squadAdded;
    SquadRemoved    squadRemoved;
};

typedef boost::rand48 WorldRNG_Priv;
typedef WorldRNG_Priv & WorldRNG;

struct World {
    typedef std::list<Int> IntList;
    typedef SpatialHash2d<Unit::Pointer> Units; //will have separate hash for buildings later if relevant to gameplay
    typedef std::list<Projectile> Projectiles;

    typedef Projectiles::iterator ProjectileIterator;
    typedef Projectiles::const_iterator ConstProjectileIterator;
    typedef std::pair<ProjectileIterator, ProjectileIterator> ProjectileRange;
    typedef std::pair<ConstProjectileIterator, ConstProjectileIterator> ConstProjectileRange;
private:
    typedef std::vector<Faction *> Factions; //no shared pointer because of fairly static number of factions
    typedef std::map<sim::Int, sim::Int> Alliances;

    HIDE_EVIL_CONSTRUCTORS(World);

    WorldRNG_Priv rng_;
    WorldSignals & signals_;
    const Landscape & landscape_;
    Units units_;
    Projectiles projectiles_;
    Factions factions_;
    Int nextTeamId_;
    Int nextProjectileId_;
public:
    World(Int seed, const Landscape & landscape, WorldSignals & signals);
    ~World();

    WorldRNG getRNG() { return rng_; }
    WorldSignals & getSignals() { return signals_; }
    const Landscape & getLandscape() const { return landscape_; }

    //units managed like this because they may be remain alive even after the death of this container.
    Units & getUnits() { return units_; }
    const Units & getUnits() const { return units_; }

    Projectile & addProjectile(const Projectile & projectile);
    ProjectileRange getProjectiles()            { return ProjectileRange(projectiles_.begin(), projectiles_.end()); }
    ConstProjectileRange getProjectiles() const { return ConstProjectileRange(projectiles_.begin(), projectiles_.end()); }
    void removeProjectile(ProjectileIterator it) { projectiles_.erase(it); }

    //factions are mangaged this way because they should never be deleted by anyone else once added to world.
    Int addFaction(Faction & faction) { factions_.push_back(&faction); return Int(factions_.size() - 1); }
    Faction & getFaction(Int id)                { return *factions_.at(id); }
    const Faction & getFaction(Int id) const    { return *factions_.at(id); }
    Int getNumFactions() const { return factions_.size(); }

    Int createTeam(const IntList & members);
};


}; //sim
}; //spelprog2

#endif //WORLD_HPP
